#include "Index.h"

StringIndex::StringIndex(const std::string & name)
:Index(name)
{
}
StringIndex::~StringIndex(){
    this->clear();
}


template<typename It>
bool _findOffset(It & it, const It & end, int & offset){
    for(; it != end; ++it){
        int size = (int)(it->second->size());
        if(offset >= size){
            offset -= size;
        }
        else{
            return true;
        }
    }
    return false;
}

std::shared_ptr<StringIndex::PkArray> StringIndex::rangeScan(int offset, int count, bool isAscend) {
    if(index.size() > 0){
        if(isAscend){
            auto it = index.begin();
            bool findOffset = _findOffset(it, index.end(), offset);
            if(findOffset == true){

                auto pks = new std::vector<int>();
                for(; count > 0 && it != index.end(); ++it){

                    auto subIt = it->second->begin();
                    if(offset > 0) {
                        std::advance(subIt, offset);
                        offset = 0;
                    }

                    for( ;count > 0 && subIt != it->second->end(); --count, ++subIt){
                        pks->push_back(*subIt);
                    }
                }
                return std::shared_ptr<PkArray>(pks);
            }
            return std::shared_ptr<PkArray>();
        }
        //desc order
        auto it = index.rbegin();
        bool findOffset = _findOffset(it, index.rend(), offset);
        if(findOffset == true){

            auto pks = new std::vector<int>();
            for(; count > 0 && it != index.rend(); ++it){

                auto subIt = it->second->rbegin();
                if(offset > 0) {
                    std::advance(subIt, offset);
                    offset = 0;
                }

                for( ;count > 0 && subIt != it->second->rend(); --count, ++subIt){
                    pks->push_back(*subIt);
                }
            }
            return std::shared_ptr<PkArray>(pks);
        }
        return std::shared_ptr<PkArray>();
    }
    return std::shared_ptr<PkArray>();
}

int StringIndex::insert(const std::string & key, const PrimaryKeyType pk) {
    auto it = index.find(key);
    if(it != index.end()){
        auto pkit = it->second->find(pk);
        if(pkit == it->second->end()){
            it->second->insert(pk);
        }
        else{
            //Error: pk is exist already
            return -1;
        }
    }
    else{
        PkContainter * pkc = new PkContainter();
        pkc->insert(pk);
        index.insert(std::make_pair(key, pkc));
    }
    return 0;
}
int StringIndex::update(const std::string & key, const PrimaryKeyType pk) {
    auto it = index.find(key);
    if(it != index.end()){
        auto pkit = it->second->find(pk);
        if(pkit != it->second->end()){
            it->second->erase(pkit);
            it->second->insert(pk);
            return 0;
        }
        //Error: pk is not exists
        return -1;
    }
    //Error IndexKey not exists
    return -1;
}
int StringIndex::remove(const std::string & key) {
    auto it = index.find(key);
    if(it != index.end()){
        if(it->second != nullptr){
            delete it->second;
        }
        index.erase(it);
        return 0;
    }
    return -1;
}
int StringIndex::remove(const std::string & key, const PrimaryKeyType pk) {
    auto it = index.find(key);
    if(it != index.end()){
        if(it->second != nullptr){
            auto pkit = it->second->find(pk);
            if(pkit != it->second->end()){
                it->second->erase(pkit);
            }
        }
        return 0;
    }
    return -1;
}

int StringIndex::clear() {
    auto it = index.begin();
    for(; it != index.end(); ++it){
        delete it->second;
    }
    return 0;
}


std::string StringIndex::toString() const {
    std::ostringstream oss;
    oss << " StringIndex:"  << getName() << std::endl;;
    auto it = index.begin();
    for(; it != index.end(); ++it){
        oss << " indexKey:[" << it->first << "]"
            << " pks:";
        auto pkit = it->second->begin();
        for(; pkit != it->second->end(); ++pkit){
             oss << "[" << *pkit << "],";
        }
        oss << std::endl;
    }
    return oss.str();
}
